package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"gitee.com/zmhfly8/cap"
)

// 全局验证码管理器，用于HTTP服务
var globalManager *cap.CaptchaManager

func main() {
	// 创建输出目录
	outputDir := "captcha_output"
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		log.Fatalf("创建输出目录失败: %v", err)
	}

	// 1. 创建验证码管理器（可选择Redis存储）
	useRedis := false // 设置为true使用Redis存储

	if useRedis {
		// Redis存储配置
		redisOptions := cap.RedisOptions{
			Addr:     "localhost:6379",
			Password: "", // 无密码
			DB:       0,
		}
		
		// 创建Redis存储的验证码管理器
		globalManager = cap.NewCaptchaManagerWithRedis(redisOptions)
		fmt.Println("使用Redis存储验证码")
	} else {
		// 默认使用内存存储
		globalManager = cap.NewCaptchaManager()
		fmt.Println("使用内存存储验证码")
	}

	// 设置验证码选项
	globalManager.SetCaptchaOptions(240, 80, 40) // 设置宽度、高度、字体大小
	globalManager.SetExpiration(10 * time.Minute) // 设置过期时间为10分钟（延长过期时间以减少过期问题）

	// 2. 生成并保存不同类型的验证码
	fmt.Println("=== 生成不同类型的验证码 ===")

	// 2.1 生成数字验证码
	numericResult, err := globalManager.GenerateNumberCaptcha(6)
	if err != nil {
		log.Fatalf("生成数字验证码失败: %v", err)
	}
	// 保存验证码图片
	numericFilePath, err := globalManager.SaveCaptchaImage(numericResult.ID, numericResult.Text, outputDir)
	if err != nil {
		log.Printf("保存数字验证码图片失败: %v", err)
	}
	fmt.Printf("数字验证码: ID=%s, 文本=%s, 保存至=%s\n",
		numericResult.ID, numericResult.Text, numericFilePath)

	// 2.2 生成字母数字组合验证码
	alphaResult, err := globalManager.GenerateAlphanumericCaptcha(6)
	if err != nil {
		log.Fatalf("生成字母数字验证码失败: %v", err)
	}
	// 保存验证码图片
	alphaFilePath, err := globalManager.SaveCaptchaImage(alphaResult.ID, alphaResult.Text, outputDir)
	if err != nil {
		log.Printf("保存字母数字验证码图片失败: %v", err)
	}
	fmt.Printf("字母数字验证码: ID=%s, 文本=%s, 保存至=%s\n",
		alphaResult.ID, alphaResult.Text, alphaFilePath)

	// 2.3 生成数学表达式验证码
	mathResult, err := globalManager.GenerateMathExpressionCaptcha()
	if err != nil {
		log.Fatalf("生成数学表达式验证码失败: %v", err)
	}
	// 保存验证码图片
	mathFilePath, err := globalManager.SaveCaptchaImage(mathResult.ID, mathResult.Text, outputDir)
	if err != nil {
		log.Printf("保存数学表达式验证码图片失败: %v", err)
	}
	fmt.Printf("数学表达式验证码: ID=%s, 文本=%s, 答案=%s, 保存至=%s\n",
		mathResult.ID, mathResult.Text, mathResult.Answer, mathFilePath)

	// 3. 验证验证码示例
	fmt.Println("\n=== 验证码验证示例 ===")

	// 模拟正确输入
	isValid := globalManager.VerifyCaptcha(alphaResult.ID, alphaResult.Text)
	fmt.Printf("验证成功的示例: ID=%s, 输入=%s, 结果=%v\n",
		alphaResult.ID, alphaResult.Text, isValid)

	// 模拟错误输入
	isValid = globalManager.VerifyCaptcha(alphaResult.ID, "wrong")
	fmt.Printf("验证失败的示例: ID=%s, 输入=wrong, 结果=%v\n",
		alphaResult.ID, isValid)

	// 4. 创建自定义颜色的验证码
	fmt.Println("\n=== 自定义颜色验证码 ===")
	customManager := cap.NewCaptchaManager()
	customManager.SetCaptchaOptions(240, 80, 40)
	customManager.SetExpiration(10 * time.Minute) // 统一过期时间设置
	// 设置自定义颜色：红色背景，白色文字
	customManager.SetColors(255, 0, 0, 255, 255, 255, 255, 255)

	customResult, err := customManager.GenerateAlphanumericCaptcha(6)
	if err != nil {
		log.Fatalf("生成自定义颜色验证码失败: %v", err)
	}
	// 保存验证码图片
	customFilePath, err := customManager.SaveCaptchaImage(customResult.ID, customResult.Text, outputDir)
	if err != nil {
		log.Printf("保存自定义颜色验证码图片失败: %v", err)
	}
	fmt.Printf("自定义颜色验证码: ID=%s, 文本=%s, 保存至=%s\n",
		customResult.ID, customResult.Text, customFilePath)

	// 5. 演示Base64编码
	fmt.Println("\n=== Base64编码示例 ===")
	base64Str, err := globalManager.GetCaptchaBase64(numericResult.ID)
	if err != nil {
		log.Printf("获取Base64编码失败: %v", err)
	} else {
		fmt.Printf("验证码Base64编码长度: %d 字符\n", len(base64Str))
		fmt.Printf("Base64编码前缀: %s...\n", base64Str[:30])
		fmt.Println("这个Base64编码可以直接用于HTML img标签的src属性")
	}

	// 6. 启动HTTP服务，提供Web示例
	fmt.Println("\n=== Web示例 ===")
	fmt.Println("启动HTTP服务器在 http://localhost:8888")
	fmt.Println("访问 /captcha 获取验证码图片")
	fmt.Println("访问 /verify?id=XXX&input=YYY 验证验证码")

	// 设置HTTP路由
	http.HandleFunc("/captcha", handleCaptcha)
	http.HandleFunc("/verify", handleVerify)

	// 启动HTTP服务器
	if err := http.ListenAndServe(":8888", nil); err != nil {
		log.Fatalf("HTTP服务器启动失败: %v", err)
	}
}

// HTTP处理函数：生成和提供验证码图片
func handleCaptcha(w http.ResponseWriter, r *http.Request) {
	// 复用全局验证码管理器，避免每次请求创建新实例
	// 生成字母数字组合验证码
	result, err := globalManager.GenerateAlphanumericCaptcha(6)
	if err != nil {
		http.Error(w, fmt.Sprintf("生成验证码失败: %v", err), http.StatusInternalServerError)
		return
	}

	// 将验证码ID设置到cookie中
	expirationTime := time.Now().Add(10 * time.Minute) // 统一过期时间
	cookie := &http.Cookie{
		Name:     "captcha_id",
		Value:    result.ID,
		Path:     "/",
		Expires:  expirationTime,
		HttpOnly: true,
	}
	http.SetCookie(w, cookie)

	// 提供验证码图片
	if err := globalManager.ServeCaptchaImage(w, r, result.ID); err != nil {
		http.Error(w, fmt.Sprintf("提供验证码图片失败: %v", err), http.StatusInternalServerError)
		return
	}

	// 输出验证码信息到服务器日志（实际应用中不应记录）
	fmt.Printf("Web验证码: ID=%s, 文本=%s\n", result.ID, result.Text)
}

// HTTP处理函数：验证验证码
func handleVerify(w http.ResponseWriter, r *http.Request) {
	// 从URL获取参数
	captchaID := r.URL.Query().Get("id")
	userInput := r.URL.Query().Get("input")

	// 从cookie获取验证码ID（如果URL中没有提供）
	if captchaID == "" {
		cookie, err := r.Cookie("captcha_id")
		if err != nil {
			http.Error(w, "验证码ID未提供", http.StatusBadRequest)
			return
		}
		captchaID = cookie.Value
	}

	if userInput == "" {
		http.Error(w, "验证码输入未提供", http.StatusBadRequest)
		return
	}

	// 使用全局验证码管理器进行验证
	isValid := globalManager.VerifyCaptcha(captchaID, userInput)

	// 返回验证结果
	w.Header().Set("Content-Type", "text/plain")
	if isValid {
		// 验证成功后移除验证码，防止重复使用
		globalManager.RemoveCaptcha(captchaID)
		fmt.Fprintf(w, "验证成功!\n验证码ID: %s\n用户输入: %s\n", captchaID, userInput)
	} else {
		fmt.Fprintf(w, "验证失败!\n验证码ID: %s\n用户输入: %s\n", captchaID, userInput)
	}

	// 输出验证结果到服务器日志
	fmt.Printf("验证请求: ID=%s, 输入=%s, 结果=%v\n", captchaID, userInput, isValid)
}
